package apobates.gui.formatter.tree;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonPrimitive;
import javafx.scene.control.TreeItem;
import java.util.HashMap;
import java.util.Map;

/**
 * JavaFx TreeItem 构造工具
 * 使用：google-gson
 */
public final class JsonNodeTreeGsonBuilder extends AbstractJsonNodeBuilder<JsonElement>{
    @Override
    public TreeItem<JsonNodeItem> build(JsonElement jsonValue) {
        TreeItem<JsonNodeItem> root = new TreeItem<>(JsonNodeItem.ofRoot());
        // 遍历json节点
        if(jsonValue.isJsonObject()){
            iteratorJsonValue(jsonValue.getAsJsonObject(), root);
        }
        if(jsonValue.isJsonArray()){
            iteratorJsonArray(jsonValue.getAsJsonArray(), root);
        }
        return root;
    }
    /**
     * 遍历Json Value/Json Object
     * @param joIns
     * @param parentNode
     */
    private void iteratorJsonValue(JsonObject joIns, TreeItem<JsonNodeItem> parentNode){
        for (String key : joIns.keySet()) {
            String name = key;
            JsonElement value = joIns.get(key);
            TreeItem<JsonNodeItem> cur = new TreeItem<>();
            if(value.isJsonArray()){
                cur.setValue(JsonNodeItem.ofArray(name));
                iteratorJsonArray(value.getAsJsonArray(), cur);
            } else if(value.isJsonObject()){
                cur.setValue(JsonNodeItem.ofObject(name));
                iteratorJsonValue(value.getAsJsonObject(), cur);
            } else if(value.isJsonPrimitive()){
                JsonNodeValueType typeName= getValueType(value);
                cur.setValue(JsonNodeItem.of(name, value.getAsJsonPrimitive().toString(), typeName));
            }
            parentNode.getChildren().add(cur);
        }
    }
    /**
     * 遍历Json Array
     * @param joArrIns
     * @param parentNode
     */
    private void iteratorJsonArray(JsonArray joArrIns, TreeItem<JsonNodeItem> parentNode){
        int index=0;
        for (JsonElement value : joArrIns) {
            TreeItem<JsonNodeItem> arrParent = new TreeItem<>(JsonNodeItem.ofArrayElement(index));
            parentNode.getChildren().add(arrParent);
            if(value.isJsonObject()){
                iteratorJsonValue(value.getAsJsonObject(), arrParent);
            }
            if(value.isJsonArray()){
                iteratorJsonArray(value.getAsJsonArray(), arrParent);
            }
            index+=1;
        }
    }
    @Override
    public JsonNodeValueType getValueType(JsonElement value) {
        if (value.isJsonNull()){
            return JsonNodeValueType.NULL;
        }
        if(!value.isJsonPrimitive()){
            return JsonNodeValueType.DEFULT;
        }
        JsonPrimitive jpv = value.getAsJsonPrimitive();
        JsonNodeValueType defVal=JsonNodeValueType.DEFULT;
        if(jpv.isBoolean()){
            defVal = JsonNodeValueType.BOOLEAN;
        }
        if(jpv.isNumber()){
            defVal = JsonNodeValueType.NUMBER;
        }
        if(jpv.isString()){
            defVal = JsonNodeValueType.STRING;
        }
        return defVal;
    }

    @Override
    public Map<JsonNodeValueType, Integer> groupValueType(JsonElement jsonValue) {
        Map<JsonNodeValueType,Integer> data = new HashMap<>();
        if(jsonValue.isJsonObject()){
            iteratorJsonValueType(jsonValue.getAsJsonObject(), data);
        }
        if(jsonValue.isJsonArray()){
            iteratorJsonArrayType(jsonValue.getAsJsonArray(), data);
        }
        return data;
    }
    private void iteratorJsonValueType(JsonObject joIns, Map<JsonNodeValueType,Integer> data){
        putIfIncrement(JsonNodeValueType.OBJECT, data);
        for (String key : joIns.keySet()) {
            JsonElement value = joIns.get(key);
            if(value.isJsonArray()){
                iteratorJsonArrayType(value.getAsJsonArray(), data);
            } else if(value.isJsonObject()){
                iteratorJsonValueType(value.getAsJsonObject(), data);
            } else {
                JsonNodeValueType typeName= getValueType(value);
                putIfIncrement(typeName, data);
            }
        }
    }
    private void iteratorJsonArrayType(JsonArray joArrIns, Map<JsonNodeValueType,Integer> data){
        putIfIncrement(JsonNodeValueType.ARRAY, data);
        for (JsonElement value : joArrIns) {
            if(value.isJsonObject()){
                iteratorJsonValueType(value.getAsJsonObject(), data);
            }
            if(value.isJsonArray()){
                iteratorJsonArrayType(value.getAsJsonArray(), data);
            }
        }
    }
}
